package handler

import (
	"github.com/DiracLee/dires-go/app/cmdline"
	"github.com/DiracLee/dires-go/app/database"
	"github.com/DiracLee/dires-go/app/payload"
	"strings"
)

// ExecFunc is interface for command Executor
// args don't include cmd name
type ExecFunc func(db database.DB, args cmdline.CmdLine) payload.Payload

// PreFunc analyses command line before enqueuing command to `multi`
// returns related write keys and read keys
type PreFunc func(args cmdline.CmdLine) ([]string, []string)

// UndoFunc returns Undo logs for the given command line
// execute from head to tail when Undo
type UndoFunc func(db database.DB, args cmdline.CmdLine) []cmdline.CmdLine


var CmdTable = make(map[string]*command)

type command struct {
	Executor ExecFunc
	Prepare  PreFunc // return related keys command
	Undo     UndoFunc
	Arity    int // allow number of args, Arity < 0 means len(args) >= -Arity
	Flags int
}

// RegisterCommand registers a new command
// Arity means allowed number of cmdArgs, Arity < 0 means len(args) >= -Arity.
// for example: the Arity of `get` is 2, `mget` is -2
func RegisterCommand(name string, executor ExecFunc, prepare PreFunc, rollback UndoFunc, arity int) {
	name = strings.ToLower(name)
	CmdTable[name] = &command{
		Executor: executor,
		Prepare:  prepare,
		Undo:     rollback,
		Arity:    arity,
	}
}
